import { Message } from 'element-ui'
export const MyMap = function(options) {
    this.$options = {                // 初始化基础参数
        el: 'aMap',
        lnglat: {                    // 默认杭州市中心坐标
            lng: 120.169904, 
            lat: 30.276903
        },  
        zoom: 17,
        city: '全国',                // 地址编码、搜索指定城市
        showInfoWindow: true,        // 显示提示窗口
        showControlBar: true,        // 显示地图简易缩放按钮
        showToolBar: true,           // 显示地图缩放工具条按钮
        showHawkEye: false,          // 显示右下角缩略地图
        showScale: false,            // 显示比例尺
        getAddress: false,           // 返回坐标对应的地址信息
        showMarker: true,            // 点击地图是否添加标记
        moreMarker: false,           // 是否支持多个标记点，在addMarker为true有效
        cb: null,
        ...options
    }
    this.$data = [{                  // 初始化数据
        title: '',
        content: '',
        lnglat: {}
    }]
    this.markers = []               // 当前窗口
    const { lng, lat } = this.$options.lnglat
    this.map = new AMap.Map(
        this.$options.el,            // 指定el
    {
        center: [lng, lat],          // 默认坐标中心点
        zoom: this.$options.zoom,    // 默认层级
        zooms: [2, 20],              // 地图显示的缩放级别范围
        showIndoorMap: false,        // 是否在有矢量底图的时候自动展示室内地图，PC默认true,移动端默认false
        dragEnable: true,            // 地图是否可通过鼠标拖拽平移，默认为true
        keyboardEnable: false,       // 地图是否可通过键盘控制，默认为true
        doubleClickZoom: true,       // 地图是否可通过双击鼠标放大地图，默认为true
        zoomEnable: true,            // 地图是否可缩放，默认值为true
        rotateEnable: true,          // 地图是否可旋转，3D视图默认为true，2D视图默认false
        viewMode: '3D',              // 地图视图模式, 默认为‘2D’，可选’3D’
        pitch: 10,                   // 3D 默认仰角度
        animateEnable: false,        // 地图平移过程中是否使用动画
        // defaultCursor: 'move',    // 地图默认鼠标样式
    })

    // 异步加载插件
    AMap.plugin([
        'AMap.Geocoder',             // 添加地理编码与逆地理编码插件
        'AMap.Scale',                // 比例尺插件
        'AMap.HawkEye',              // 缩略地图插件
        'AMap.ControlBar',           // 组合了旋转、倾斜、复位在内的地图控件
        'AMap.ToolBar',              // 工具条插件
        'AMap.PlaceSearch',          // 搜索插件
        'AMap.MoveAnimation',        // marker.moveTo 需要的动画插件
    ], () => {
        this.geoc = new AMap.Geocoder(
        {
            city: this.$options.city,// city 指定进行编码查询的城市，支持城市名、adcode 和 citycode
            // batch: false          // 非批量查询
        })

        this.mSearch = new AMap.PlaceSearch({
            city: this.$options.city,
            type: '',                // 数据类别
            pageSize: 1,             // 每页结果数，默认10
            pageIndex: 1,            // 请求页码，默认1
            extensions: 'base',      // 返回信息详略，默认base(基本信息)
        })

        if (this.$options.showControlBar) {
            this.controlBar = new AMap.ControlBar({
                offset: new AMap.Pixel(10, 10),
                showControlButton: true, // 是否显示倾斜、旋转按钮
                position: {
                    top: '10px',
                    left: '10px'
                }
            })
            
            // addTo 默认是开启显示 .show()显示 .hide() 关闭
            this.controlBar.addTo(this.map)   
        }

        if (this.$options.showToolBar) {
            this.toolBar = new AMap.ToolBar({
                offset: new AMap.Pixel(10, 10),
                position: {
                    top: '110px',
                    left: '41px'
                }
            })
            this.toolBar.addTo(this.map) 
        }

        if (this.$options.showHawkEye) {
            this.hawkEye = new AMap.HawkEye({
                autoMove: true,
                showButton: true,
                isOpen: true,
                showRectangle: true
            })
            this.hawkEye.addTo(this.map)       
        }

        if (this.$options.showScale) {
            this.scale = new AMap.Scale()
            this.scale.addTo(this.map)      
        }
    })

    // 地图添加点击事件
    this.map.on("click", e => {
        e.index = 0
        this.getAddress(e.lnglat, e.index)
        // 若为添加新标记
        if (this.$options.moreMarker) {
            e.index = this.$data.length
            this.setData(
                { title: '标题' + e.index, content: '内容' + e.index, lnglat: e.lnglat }, 
                e.index
            )
        }
        this.setMarker(e.lnglat, false, e.index)
        this.callBack(e)
    })
}
// MyMap 原型方法
MyMap.prototype = {
    setData(data, index = 0) {
        this.$data[index] = {
            ...this.$data[index],
            ...data
        }
    },
    // 格式化lnglat
    formatLnglat(lnglat) {
        if (Object.prototype.toString.call(lnglat) === '[object Array]') {
            return lnglat
        } else if (Object.prototype.toString.call(lnglat) === '[object Object]') {
            return new AMap.LngLat(lnglat.lng, lnglat.lat)
        } else if (typeof value === 'string') {
            return lnglat.split(",")
        }
    },
    // 设置地图属性状态
    setStatus(obj) {
        this.map.setStatus(obj)
    },
    // 设置marker
    setMarker(lnglat, center = false, index = 0, forceShowMarker = false) {
        if (!this.$options.showMarker) return
        const position = this.formatLnglat(lnglat)
        const marker = this.markers[index]
        if (!this.$options.moreMarker && marker) {
            // 点击地图把 marker 移动到指定位置
            marker.moveTo(
                position, 
                {
                    autoRotation: false,     // 点标记方向是否沿路径旋转
                    duration: 100            // 每段动画持续时长, 单位：ms
                }
            )
            this.setData({ lnglat: position }, index) 
            if (center) { this.setCenter(position) }
        } else {
            this.addMarker(position, center, index, forceShowMarker)
        }
    },
    // 添加marker
    addMarker(position, center = false, index = 0, forceShowMarker = false) {
        let marker = null
        position = this.formatLnglat(position)

        // 判断是否存在相同坐标数据
        if (this.$options.moreMarker) {
            marker = this.markers[index]
        }

        // 创建标注
        if (!marker) {
            this.markers[index] = new AMap.Marker({
                position,
                visible: true,
                title: '',                       // 鼠标滑过点标记时的文字提示
                draggable: true,                 // 允许拖拽
                zIndex: index + 1,               // 层级
                extData: {                       // 自定义属性
                    index                        // 对应的提示框数组下标
                }                      
            })
            marker = this.markers[index]
        
            // 标记点事件
            // 关闭和显示提示窗口
            marker.on('click', () => {
                this.setInfoWindow({ position, toggle: true, index })
            })
            
            // moveTo()方法触发的标记点移动事件, 在拖拽事件中不会触发此事件
            marker.on('moving', e => {
                position = this.formatLnglat(marker.getPosition())
                this.setInfoWindow({ position, move: true, index })
            })
    
            // 标记点拖拽开始
            marker.on('dragstart', e => {})
    
            // 标记点拖拽进行中
            marker.on('dragging', e => {
                /**
                 * 注意 e.lnglat 坐标不是marker icon 箭头底部所指向的坐标，而是和鼠标点击时产生的坐标 这是个BUG
                 * 所以这个坐标是有偏差的，我们需要通过getPosition() 方法来获取当前 marker 的实际坐标
                 */
                position = this.formatLnglat(marker.getPosition())
                this.setInfoWindow({ position, move: true, index })
            })
    
            // 标记点拖拽完成
            marker.on('dragend', e => {
                const lnglat = marker.getPosition()
                position = this.formatLnglat(lnglat)
                this.setData({ lnglat: position }, index)
                this.callBack({ lnglat, index })
                this.getAddress(position, index)
            })
        }

        marker.addTo(this.map)               // 将标注添加到地图中
        // this.map.add(marker)              // 将标注添加到地图中，效果和上面一样
        this.setInfoWindow({ position, index, forceShowMarker }) // 初始窗口  
        if (center) {
            this.setCenter(position)         // 设置中心点
        }
    },
    // 清除marker
    clearMarker(center = false, index = 0) {
        const marker = this.markers[index]
        marker && this.map.remove(marker)
        if (center) this.setCenter()
    },
    // 设置提示窗口
    setInfoWindow({ position, toggle, move, index = 0, forceShowMarker = false }) {
        if (!this.$options.showInfoWindow) return

        // 窗口内容信息
        const { title, content } = this.$data[index]
        const info = `
            <div class="map-infowindow">
                <div class="map-infowindow-title">${title}</div>
                <div>${content}</div>
            </div>
        `
        if (!this.infoWindow) {
            this.infoWindow = new AMap.InfoWindow({
                // isCustom: true,                   // 自定义窗口信息
                // closeWhenClickMap: true,          // 允许点击地图关闭窗口
                anchor: 'bottom-center',             // 箭头和标记点的位置
                content: info,                       // 使用默认信息窗体框样式，显示信息内容
                offset: new AMap.Pixel(0, -34),
                autoMove: false,                     // 是否自动调整窗体到视野内, 但当使用setCenter的时候要关闭这个，不然无法正确设置中心点
                extData: {                           // 自定义属性
                    index                            // 对应的提示框数组下标
                } 
            })
        } else {
            const _index = this.infoWindow.getExtData().index

            // 点击标记打开或关闭
            if (toggle) {
                // 只针对当前标记
                if (_index === index && this.infoWindow.getIsOpen()) {
                    return this.infoWindow.close()
                }
            // 若为移动标记
            } else if (move) {
                // 当前标记未开提示窗口，则返回
                if (_index !== index || !this.infoWindow.getIsOpen()) {
                    return
                }
            // 窗口初始
            } else {
                // 当前窗口未显示，则初始新的标记也不显示窗口
                if (!forceShowMarker && !this.infoWindow.getIsOpen()) return
            }
            if ( title || content ) {
                this.infoWindow.setExtData({ index })
                this.infoWindow.setContent(info)
            }
        }
        if ( title || content ) {
            this.infoWindow.open(this.map, position)
        }
    },
    // 移动标注、点击地图 回调函数
    callBack(e) {
        const cb = this.$options.cb
        const res = { index: e.index }
        if (e.lnglat) {
            res.lng = e.lnglat.lng
            res.lat = e.lnglat.lat
        }
        if (e.regeocode) res.regeocode = e.regeocode
        typeof cb === 'function' && cb(res, this.$data)
    },
    // 设置地图层级与中心点
    setCenterAndZoom(position) {
        if (!position) {
            position = this.formatLnglat(this.$options.lnglat)
        }
        this.map.setZoomAndCenter(this.$options.zoom, position)
    },
    // 设置地图缩放层级
    setZoom(zoom) {
        this.map.setZoom(zoom)
    },
    // 获取地图缩放层级
    getZoom() {
        return this.map.getZoom()
    },
    // 设置地图中心点
    setCenter(position = null) {
        if (!position) {
            position = this.formatLnglat(this.$options.lnglat)
        }
        this.map.setCenter(position)
        // 当地图覆盖物较多，我们可以通过下面方法根据覆盖物范围调整视野, 将地图调整到合适的缩放等级和中心点
        // this.map.setFitView()
    },
    // 获取地图中心点
    getCenter() {
        return map.getCenter()
    },
    // 根据地址获取经纬度, 并添加标记点
    getLocation(obj) {
        const { title, address, content } = obj
        address && this.geoc.getLocation(address, (status, result) => {
            if (status === 'complete' && result.info === 'OK') {
                if (result.geocodes[0]) {
                    const location = result.geocodes[0].location
                    const index = this.hasData(location)
                    this.setData({ title, content, lnglat: location }, index)
                    this.setMarker(location, true, index, true)
                    return this.callBack({ lnglat: location, index })
                }     
            }
            Message({
                type: 'error',
                message: '地址解析失败'
            })
        })
    },
    // 根据经纬度获取地址 参数可以是单个或数组
    getAddress(position, index = 0) {
        if (!this.$options.getAddress) return
        position = this.formatLnglat(position)
        this.geoc.getAddress(position, (status, result) => {
            if (status === 'complete' && result.info === 'OK') {
                if (result.regeocode) {
                    return this.callBack({ regeocode: result.regeocode, index })
                }
            }
            Message({
                type: 'error',
                message: '地址逆解析失败'
            })
        })
    },
    // 根据地址搜索返回经纬度
    search(obj) {
        const { title, address, content } = obj
        this.mSearch.search(address, (status, result) => {
            if (status === 'complete' && result.info === 'OK') {
                if (result.poiList.count > 0) {
                    const location = result.poiList.pois[0].location
                    const index = this.hasData(location)
                    this.setData({ title, content, lnglat: location }, index)
                    this.setMarker(location, true, index, true)
                    return this.callBack({ lnglat: location, index })
                }
            }
            Message({
                type: 'error',
                message: '位置标注失败'
            })
        })
    },
    hasData(location) {
        let index = 0
        if (this.$options.moreMarker) {
            index = this.$data.findIndex(data => {
                const { lng, lat } = data.lnglat
                if (lng == location.lng && lat == location.lat) {
                    return data
                }
            })
            if (index < 0) index = this.$data.length
        }
        return index
    }
}